package com.ssy.lingxi.order.serviceimpl.base;

import cn.hutool.json.JSONUtil;
import com.ssy.lingxi.common.constant.Constants;
import com.ssy.lingxi.common.constant.basic.UserLoginSourceEnum;
import com.ssy.lingxi.common.exception.BusinessException;
import com.ssy.lingxi.common.model.dto.UserLoginCacheDTO;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.component.redis.service.IRedisStringUtils;
import com.ssy.lingxi.component.redis.service.IRedisUtils;
import com.ssy.lingxi.order.model.constant.OrderServiceContants;
import com.ssy.lingxi.order.model.dto.PayResultDTO;
import com.ssy.lingxi.order.model.dto.PaymentCacheDTO;
import com.ssy.lingxi.order.service.base.IBaseCacheService;
import com.ssy.lingxi.order.utils.OrderStringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

/**
 * 会员用户缓存工具类实现
 * @author 万宁
 * @version 2.0.0
 * @date 2020-07-03
 */
@Service
public class BaseCacheServiceImpl implements IBaseCacheService {
    private static final Logger logger = LoggerFactory.getLogger(BaseCacheServiceImpl.class);

    @Resource
    private IRedisUtils redisUtils;

    @Resource
    private IRedisStringUtils redisStringUtils;

    @Resource
    private HttpServletRequest httpServletRequest;

    /**
     * 获取用户信息
     *
     * @param headers Http头部信息
     * @return 用户信息实体
     */
    @Override
    public UserLoginCacheDTO checkUserFromCache(HttpHeaders headers) {
        //HTTP header是否包含了token字段
        if(!headers.containsKey(OrderServiceContants.USER_TOKEN_HTTP_HEADERS_KEY)) {
            throw new BusinessException(ResponseCode.TOKEN_DOES_NOT_EXIST_IN_CACHE);
        }

        //HTTP header是否包含了source字段
        if(!headers.containsKey(OrderServiceContants.USER_LOGIN_SOURCE_HTTP_HEADERS_KEY)) {
            throw new BusinessException(ResponseCode.REQUEST_HEADER_ERROR);
        }

        //HTTP header的token字段是否为空
        String token = headers.getFirst(OrderServiceContants.USER_TOKEN_HTTP_HEADERS_KEY);
        if(!StringUtils.hasLength(token)) {
            throw new BusinessException(ResponseCode.TOKEN_DOES_NOT_EXIST_IN_CACHE);
        }

        //HTTP header的source字段是否为空
        String source = headers.getFirst(OrderServiceContants.USER_LOGIN_SOURCE_HTTP_HEADERS_KEY);
        if(!StringUtils.hasLength(source) || !UserLoginSourceEnum.toStringList().contains(source)) {
            throw new BusinessException(ResponseCode.REQUEST_HEADER_ERROR);
        }

        //redis中是否有token
        Object tokenObj = redisUtils.get(token,Constants.REDIS_USER_INDEX);
        if(tokenObj == null) {
            throw new BusinessException(ResponseCode.TOKEN_DOES_NOT_EXIST_IN_CACHE);
        }

        UserLoginCacheDTO cacheDTO = JSONUtil.parse(tokenObj).toBean(UserLoginCacheDTO.class);

        //用户信息反序列化是否成功
        if(cacheDTO == null) {
            throw new BusinessException(ResponseCode.TOKEN_DOES_NOT_EXIST_IN_CACHE);
        }

        // source字段是否与登录后缓存的loginFrom字段相同
        if(!cacheDTO.getLoginSource().equals(Integer.valueOf(source))) {
            throw new BusinessException(ResponseCode.LOGIN_SOURCE_NOT_EQUALS_TO_HTTP_HEADER_SOURCE);
        }

        //数据权限标记
//        Object authFlag = Objects.isNull(httpServletRequest) ? null : httpServletRequest.getAttribute(DataAuthConstant.HTTP_ATTRIBUTE_ORDER_AUTH_FLAG);
//        cacheDTO.setHasDataAuth(Objects.nonNull(authFlag));

        return cacheDTO;
    }

    /**
     * 是否从平台后台登录
     * @param headers HttpHeaders信息
     * @return 用户信息
     */
    @Override
    public UserLoginCacheDTO needLoginFromManagePlatform(HttpHeaders headers) {
        UserLoginCacheDTO loginCacheDTO = checkUserFromCache(headers);
        if(loginCacheDTO.getLoginSource() == null || !loginCacheDTO.getLoginSource().equals(UserLoginSourceEnum.BUSINESS_MANAGEMENT_PLATFORM.getCode())) {
            throw new BusinessException(ResponseCode.NEED_LOGIN_FROM_MANAGE_PLATFORM);
        }
        return loginCacheDTO;
    }

    /**
     * 是否从业务平台登录
     * @param headers HttpHeaders信息
     * @return 用户信息
     */
    @Override
    public UserLoginCacheDTO needLoginFromBusinessPlatform(HttpHeaders headers) {
        UserLoginCacheDTO loginCacheDTO = checkUserFromCache(headers);
        if(loginCacheDTO.getLoginSource() == null || (!loginCacheDTO.getLoginSource().equals(UserLoginSourceEnum.BUSINESS_WEB.getCode()) && !loginCacheDTO.getLoginSource().equals(UserLoginSourceEnum.BUSINESS_MOBILE.getCode()))) {
            throw new BusinessException(ResponseCode.NEED_LOGIN_FROM_BUSINESS_CENTER);
        }
        return loginCacheDTO;
    }

    /**
     * 是否从App客户端登录
     *
     * @param headers HttpHeaders信息
     * @return 缓存的用户信息
     */
    @Override
    public UserLoginCacheDTO needLoginFromMobile(HttpHeaders headers) {
        UserLoginCacheDTO loginCacheDTO = checkUserFromCache(headers);
        if(loginCacheDTO.getLoginSource() == null || !loginCacheDTO.getLoginSource().equals(UserLoginSourceEnum.BUSINESS_MOBILE.getCode())) {
            throw new BusinessException(ResponseCode.NEED_LOGIN_FROM_BUSINESS_APP);
        }
        return loginCacheDTO;
    }

    /**
     * 校验Web端请求的HttpHeader中是否包含source = 1
     * @param headers HttpHeaders信息
     */
    @Override
    public void checkWebRequestHeader(HttpHeaders headers) {
        String source = headers.getFirst(OrderServiceContants.USER_LOGIN_SOURCE_HTTP_HEADERS_KEY);
        if(!StringUtils.hasLength(source) || !source.equals(String.valueOf(UserLoginSourceEnum.BUSINESS_WEB.getCode()))) {
            throw new BusinessException(ResponseCode.REQUEST_HEADER_ERROR);
        }
    }

    /**
     * 校验移动端请求的HttpHeader中是否包含source = 2
     * @param headers HttpHeaders信息
     */
    @Override
    public void checkMobileRequestHeader(HttpHeaders headers) {
        String source = headers.getFirst(OrderServiceContants.USER_LOGIN_SOURCE_HTTP_HEADERS_KEY);
        if(!StringUtils.hasLength(source) || !source.equals(String.valueOf(UserLoginSourceEnum.BUSINESS_MOBILE.getCode()))) {
            throw new BusinessException(ResponseCode.REQUEST_HEADER_ERROR);
        }
    }

    /**
     * 校验平台后台请求的HttpHeader中是否包含source = 99
     * @param headers HttpHeaders信息
     */
    @Override
    public void checkPlatformRequestHeader(HttpHeaders headers) {
        String source = headers.getFirst(OrderServiceContants.USER_LOGIN_SOURCE_HTTP_HEADERS_KEY);
        if(!StringUtils.hasLength(source) || !source.equals(String.valueOf(UserLoginSourceEnum.BUSINESS_MANAGEMENT_PLATFORM.getCode()))) {
            throw new BusinessException(ResponseCode.REQUEST_HEADER_ERROR);
        }
    }

    /**
     * 缓存预下单信息
     *
     * @param key   Redis Key值
     * @param value 字符串
     */
    @Override
    public void cachePreOrder(String key, String value) {
        redisStringUtils.set(key, value, OrderServiceContants.PRE_ORDER_CACHE_TIME_SECONDS, 0);
    }

    /**
     * 查询预下单信息
     *
     * @param key Redis Key值
     * @return 字符串
     */
    @Override
    public String getPreOrder(String key) {
        return redisStringUtils.get(key, 0);
    }

    /**
     * 删除预下单信息
     *
     * @param key Redis Key值
     */
    @Override
    public void deletePreOrder(String key) {
        redisStringUtils.del(key, 0);
    }

    /**
     * 缓存支付是否成功
     *
     * @param tradeNo    订单交易号
     * @param paySuccess 是否成功
     */
    @Override
    public void cacheOrderPayResult(String tradeNo, Boolean paySuccess) {
        final String key = OrderServiceContants.PAY_RESULT_CACHE_PREFIX.concat(tradeNo);
        PayResultDTO resultDTO = new PayResultDTO(paySuccess);
        Boolean cacheSuccess = redisUtils.set(key, resultDTO, OrderServiceContants.PAY_RESULT_CACHE_SECONDS, Constants.REDIS_ORDER_INDEX);
        logger.info("缓存支付结果，订单tradeNo: " + tradeNo + ", 支付成功:" + paySuccess + ", 缓存结果:" + cacheSuccess);
    }

    /**
     * 查询支付结果
     *
     * @param tradeNo 订单交易号
     * @return 查询结果
     */
    @Override
    public PayResultDTO findOrderPayResult(String tradeNo) {
        final String key = OrderServiceContants.PAY_RESULT_CACHE_PREFIX.concat(tradeNo);

        PayResultDTO resultDTO = redisUtils.get(key, Constants.REDIS_ORDER_INDEX, PayResultDTO.class);
        logger.info("读取缓存支付结果，订单tradeNo: " + tradeNo + ", 缓存内容:" + OrderStringUtil.serializeObject(resultDTO));
        return resultDTO;
        //return redisUtils.get(key, Constants.REDIS_ORDER_INDEX, PayResultDTO.class);
    }

    /**
     * 缓存支付的用户、支付记录等信息
     *
     * @param attach      （在线支付）订单的透传参数
     * @param paymentCache 缓存内容
     */
    @Override
    public void cacheOrderPayment(String attach, PaymentCacheDTO paymentCache) {
        //to delete
        logger.info("缓存支付信息, Key = " + attach);
        logger.info("缓存支付信息, 内容：" + OrderStringUtil.serializeObject(paymentCache));
        redisUtils.set(attach, paymentCache, OrderServiceContants.ORDER_PAYMENT_CACHE_SECONDS, Constants.REDIS_ORDER_INDEX);
    }

    /**
     * 查询缓存的支付用户、支付记录等信息
     *
     * @param attach （在线支付）订单的透传参数
     * @return 支付用户、支付记录等信息
     */
    @Override
    public PaymentCacheDTO findOrderPayment(String attach) {
        //to delete

        PaymentCacheDTO cacheDTO = redisUtils.get(attach, Constants.REDIS_ORDER_INDEX, PaymentCacheDTO.class);
        logger.info("读取缓存支付信息, Key = " + attach);
        logger.info("读取缓存支付信息, 内容：" + OrderStringUtil.serializeObject(cacheDTO));

        return cacheDTO;
        //return redisUtils.get(attach, Constants.REDIS_ORDER_INDEX, PaymentCacheDTO.class);
    }

    /**
     * 删除缓存的支付用户、支付记录等信息
     *
     * @param attach （在线支付）订单的透传参数
     */
    @Override
    public void deleteOrderPayment(String attach) {
        redisUtils.del(attach, Constants.REDIS_ORDER_INDEX);
    }

    /**
     * 通过token获取用户登录信息
     * @param token HttpHeaders信息
     * @return 缓存的用户信息
     */
    @Override
    public UserLoginCacheDTO needLoginFromBusinessPlatform(String token) {
        //redis中是否有token
        Object tokenObj = redisUtils.get(token, Constants.REDIS_USER_INDEX);
        if (tokenObj == null) {
            throw new BusinessException(ResponseCode.TOKEN_DOES_NOT_EXIST_IN_CACHE);
        }

        return JSONUtil.parse(tokenObj).toBean(UserLoginCacheDTO.class);
    }
}
